package com.ocean.web.util.ftpuputil;

import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;

import java.io.*;
import java.util.UUID;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;

/**
 * FTP 大文件上传工具类（终极版）
 * 特性：排队机制+断点续传+进度监听+防100%卡住+同时返回ID+状态+超时兜底
 */
public class FtpLargeFileUploader {

    // ------------------------------ 核心配置（可根据需求调整）------------------------------
    private static final int BUFFER_SIZE = 8 * 1024 * 1024; // 8MB缓冲区（平衡性能和内存）
    private static final int DEFAULT_TIMEOUT = 300000; // 5分钟（连接/传输超时）
    private static final int PENDING_COMMAND_TIMEOUT = 30000; // 30秒（服务器确认超时，解决100%卡住）
    private static final int CONTROL_KEEP_ALIVE_TIMEOUT = 30; // 30秒（控制连接保活）
    private static final int CORE_POOL_SIZE = 2; // 核心并发数（根据FTP服务器承载调整）
    private static final int MAX_POOL_SIZE = 3; // 最大并发数
    private static final long KEEP_ALIVE_TIME = 60; // 线程空闲存活时间（秒）
    private static final int QUEUE_CAPACITY = 10; // 排队队列容量（超出则拒绝）
    private static final long FINAL_DATA_WAIT = 500; // 上传100%后等待时间（毫秒，确保最后一块数据发送）

    // ------------------------------ 排队机制核心组件 ------------------------------
    private static final BlockingQueue<Runnable> UPLOAD_QUEUE = new ArrayBlockingQueue<>(QUEUE_CAPACITY);
    private static final ThreadPoolExecutor UPLOAD_EXECUTOR = new ThreadPoolExecutor(
            CORE_POOL_SIZE,
            MAX_POOL_SIZE,
            KEEP_ALIVE_TIME,
            TimeUnit.SECONDS,
            UPLOAD_QUEUE,
            new ThreadFactory() { // 自定义线程名，方便排查
                private final AtomicInteger threadNum = new AtomicInteger(1);
                @Override
                public Thread newThread(Runnable r) {
                    return new Thread(r, "ftp-upload-thread-" + threadNum.getAndIncrement());
                }
            },
            new RejectedExecutionHandler() { // 队列满拒绝策略（已修复）
                @Override
                public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
                    if (r instanceof UploadTask) {
                        UploadTask task = (UploadTask) r;
                        // 设置队列满状态
                        task.setResult(UploadStatus.QUEUE_FULL, "上传队列已满，请稍后再试（当前容量：" + QUEUE_CAPACITY + "）");
                        // 触发 latch 唤醒等待线程（已确保 resultLatch 存在）
                        if (task.resultLatch != null && task.resultLatch.getCount() > 0) {
                            task.resultLatch.countDown();
                        }
                        // 移除无用任务缓存
                        TASK_CACHE.remove(task.getTaskId());
                    }
                }
            }
    );

    // 任务状态缓存（key：任务ID，value：任务信息）
    private static final ConcurrentHashMap<String, UploadTask> TASK_CACHE = new ConcurrentHashMap<>();

    // ------------------------------ 上传状态枚举 ------------------------------
    public enum UploadStatus {
        SUCCESS("上传成功"),
        FAILED("上传失败"),
        FILE_NOT_FOUND("本地文件不存在"),
        FTP_CONNECT_FAILED("FTP 连接失败"),
        FTP_LOGIN_FAILED("FTP 登录失败"),
        FTP_DIRECTORY_CREATE_FAILED("FTP 目录创建失败"),
        FILE_ALREADY_EXISTS("文件已存在（未重新上传）"),
        RESUME_UPLOAD_SUCCESS("断点续传成功"),
        RESUME_UPLOAD_FAILED("断点续传失败"),
        SERVER_TIMEOUT("服务器确认超时（文件可能已上传成功）"),
        QUEUE_FULL("上传队列已满"),
        TASK_CANCELLED("任务已取消"),
        UPLOADING("上传中");

        private final String desc;
        UploadStatus(String desc) { this.desc = desc; }
        public String getDesc() { return desc; }
    }

    // ------------------------------ 上传进度监听器 ------------------------------
    public interface UploadProgressListener {
        /**
         * 进度更新回调
         * @param uploadedSize 已上传字节数
         * @param totalSize 总字节数
         * @param progress 进度百分比（0-100）
         */
        void onProgress(long uploadedSize, long totalSize, double progress);
    }

    // ------------------------------ 上传结果回调接口（异步方案用）------------------------------
    public interface UploadResultCallback {
        /**
         * 上传完成回调
         * @param finalResult 最终结果（成功/失败）
         */
        void onComplete(UploadResult finalResult);
    }

    // ------------------------------ 返回结果封装类（ID+状态+描述）------------------------------
    public static class UploadResult {
        private String taskId;       // 任务唯一ID
        private UploadStatus status; // 任务当前状态
        private String message;      // 状态描述/错误信息

        public UploadResult(String taskId, UploadStatus status, String message) {
            this.taskId = taskId;
            this.status = status;
            this.message = message;
        }

        // Getter（调用方获取属性）
        public String getTaskId() { return taskId; }
        public UploadStatus getStatus() { return status; }
        public String getMessage() { return message; }
    }

    // ------------------------------ 上传任务封装（核心逻辑，已包含 resultLatch）------------------------------
    public static class UploadTask implements Runnable {
        private final String taskId;
        private final String ftpHost;
        private final int ftpPort;
        private final String ftpUsername;
        private final String ftpPassword;
        private final String localFilePath;
        private final String remoteDir;
        private final String remoteFileName;
        private final boolean overwrite;
        private final UploadProgressListener listener;
        private final UploadResultCallback resultCallback;

        // 同步等待核心：CountDownLatch（确保存在）
        private final CountDownLatch resultLatch;
        // 最终结果缓存
        private UploadResult finalResult;

        // 线程安全的状态/进度存储
        private final AtomicReference<UploadStatus> status = new AtomicReference<>(UploadStatus.UPLOADING);
        private final AtomicLong uploadedSize = new AtomicLong(0);
        private final AtomicLong totalSize = new AtomicLong(0);
        private String errorMsg;
        private boolean cancelled = false;

        // ------------------------------ 构造器（同步方案用，接收 resultLatch）------------------------------
        public UploadTask(
                String ftpHost, int ftpPort, String ftpUsername, String ftpPassword,
                String localFilePath, String remoteDir, String remoteFileName,
                boolean overwrite, UploadProgressListener listener,
                CountDownLatch resultLatch) {
            this(ftpHost, ftpPort, ftpUsername, ftpPassword, localFilePath, remoteDir, remoteFileName,
                    overwrite, listener, null, resultLatch);
        }

        // ------------------------------ 构造器（异步方案用，含回调）------------------------------
        public UploadTask(
                String ftpHost, int ftpPort, String ftpUsername, String ftpPassword,
                String localFilePath, String remoteDir, String remoteFileName,
                boolean overwrite, UploadProgressListener listener,
                UploadResultCallback resultCallback) {
            this(ftpHost, ftpPort, ftpUsername, ftpPassword, localFilePath, remoteDir, remoteFileName,
                    overwrite, listener, resultCallback, new CountDownLatch(1));
        }

        // ------------------------------ 核心构造器（统一初始化）------------------------------
        private UploadTask(
                String ftpHost, int ftpPort, String ftpUsername, String ftpPassword,
                String localFilePath, String remoteDir, String remoteFileName,
                boolean overwrite, UploadProgressListener listener,
                UploadResultCallback resultCallback, CountDownLatch resultLatch) {
            this.taskId = UUID.randomUUID().toString().replace("-", "");
            this.ftpHost = ftpHost;
            this.ftpPort = ftpPort;
            this.ftpUsername = ftpUsername;
            this.ftpPassword = ftpPassword;
            this.localFilePath = localFilePath;
            this.remoteDir = remoteDir;
            this.remoteFileName = remoteFileName;
            this.overwrite = overwrite;
            this.listener = listener;
            this.resultCallback = resultCallback;
            this.resultLatch = resultLatch; // 赋值给成员变量（关键）
            TASK_CACHE.put(this.taskId, this);
        }

        @Override
        public void run() {
            // 若任务已取消，直接返回
            if (cancelled) {
                setResult(UploadStatus.TASK_CANCELLED, "任务已取消");
                return;
            }

            // 1. 本地文件校验
            File localFile = new File(localFilePath);
            if (!localFile.exists() || !localFile.isFile()) {
                setResult(UploadStatus.FILE_NOT_FOUND, "本地文件不存在：" + localFilePath);
                return;
            }
            long fileSize = localFile.length();
            if (fileSize <= 0) {
                setResult(UploadStatus.FAILED, "文件大小为0，无法上传");
                return;
            }
            totalSize.set(fileSize);

            FTPClient ftpClient = null;
            OutputStream outputStream = null;
            InputStream inputStream = null;
            long remoteFileSize = 0;
            boolean isResume = false;

            try {
                // 2. 初始化FTP客户端（带保活+超时）
                ftpClient = createFtpClient();

                // 3. 连接FTP服务器（带超时）
                boolean connected = false;
                try {
                    ftpClient.connect(ftpHost, ftpPort);
                    connected = FTPReply.isPositiveCompletion(ftpClient.getReplyCode());
                } catch (Exception e) {
                    setResult(UploadStatus.FTP_CONNECT_FAILED, "FTP连接失败：" + e.getMessage());
                    return;
                }
                if (!connected) {
                    setResult(UploadStatus.FTP_CONNECT_FAILED, "FTP服务器拒绝连接（响应码：" + ftpClient.getReplyCode() + "）");
                    return;
                }

                // 4. 登录FTP服务器
                if (!ftpClient.login(ftpUsername, ftpPassword)) {
                    setResult(UploadStatus.FTP_LOGIN_FAILED, "FTP用户名或密码错误");
                    return;
                }

                // 5. 配置FTP上传参数（被动模式+二进制传输）
                configureFtpClient(ftpClient);

                // 6. 创建远程目录（递归创建多级目录）
                if (!createRemoteDirectory(ftpClient, remoteDir) || !ftpClient.changeWorkingDirectory(remoteDir)) {
                    setResult(UploadStatus.FTP_DIRECTORY_CREATE_FAILED, "创建远程目录失败：" + remoteDir);
                    return;
                }

                // 7. 断点续传逻辑（校验远程文件）
                FTPFile[] remoteFiles = ftpClient.listFiles(remoteFileName);
                boolean fileExists = remoteFiles != null && remoteFiles.length > 0;
                if (fileExists) {
                    if (overwrite) {
                        // 覆盖模式：删除已存在文件
                        boolean deleteSuccess = ftpClient.deleteFile(remoteFileName);
                        if (!deleteSuccess) {
                            setResult(UploadStatus.FAILED, "覆盖模式：删除远程已存在文件失败");
                            return;
                        }
                    } else {
                        // 断点续传：校验文件大小
                        remoteFileSize = remoteFiles[0].getSize();
                        if (remoteFileSize >= fileSize) {
                            setResult(UploadStatus.FILE_ALREADY_EXISTS, "远程文件已存在且大小不小于本地文件（远程：" + remoteFileSize / (1024*1024) + "MB，本地：" + fileSize / (1024*1024) + "MB）");
                            return;
                        }
                        uploadedSize.set(remoteFileSize);
                        isResume = true;
                        // 回调初始进度（已上传部分）
                        if (listener != null) {
                            double progress = (remoteFileSize * 100.0) / fileSize;
                            listener.onProgress(remoteFileSize, fileSize, progress);
                        }
                    }
                }

                // 8. 打开文件流（上传核心流）
                outputStream = ftpClient.storeFileStream(remoteFileName);
                inputStream = new FileInputStream(localFile);

                // 9. 断点续传：跳过已上传部分（优化跳过逻辑，避免失败）
                if (uploadedSize.get() > 0) {
                    long skipped = 0;
                    long maxRetry = 3; // 最多重试3次
                    while (skipped < uploadedSize.get() && maxRetry-- > 0 && !cancelled) {
                        long skip = inputStream.skip(uploadedSize.get() - skipped);
                        if (skip == 0) {
                            // 跳过失败，重置流重新跳过
                            inputStream.close();
                            inputStream = new FileInputStream(localFile);
                            skipped = 0;
                            continue;
                        }
                        skipped += skip;
                    }
                    if (skipped < uploadedSize.get()) {
                        // 多次重试仍失败，放弃断点续传，重新上传
                        uploadedSize.set(0);
                        isResume = false;
                        inputStream.close();
                        inputStream = new FileInputStream(localFile);
                    } else {
                        uploadedSize.set(skipped);
                    }
                }

                // 10. 分块上传（核心传输逻辑，带进度回调）
                byte[] buffer = new byte[BUFFER_SIZE];
                int bytesRead;
                while ((bytesRead = inputStream.read(buffer)) != -1 && !cancelled) {
                    outputStream.write(buffer, 0, bytesRead);
                    uploadedSize.addAndGet(bytesRead);

                    // 进度回调（优化频率：每8MB或进度整1%回调一次）
                    if (listener != null) {
                        double progress = Math.min(100.0, (uploadedSize.get() * 100.0) / totalSize.get());
                        long lastProgress = (int) ((uploadedSize.get() - bytesRead) * 100.0 / totalSize.get());
                        if (uploadedSize.get() % BUFFER_SIZE == 0 || (int) progress > lastProgress) {
                            listener.onProgress(uploadedSize.get(), totalSize.get(), progress);
                        }
                    }
                }

                // 检查是否被取消
                if (cancelled) {
                    setResult(UploadStatus.TASK_CANCELLED, "任务执行中被取消");
                    return;
                }

                // 11. 上传100%后优化：等待最后一块数据发送到服务器
                if (uploadedSize.get() == totalSize.get()) {
                    Thread.sleep(FINAL_DATA_WAIT);
                }

                // 12. 关键收尾：正确关闭流（先关输出流，告知服务器传输结束）
                outputStream.flush(); // 强制刷新缓冲区，确保最后一块数据发送
                closeStream(outputStream);
                outputStream = null;
                closeStream(inputStream);
                inputStream = null;

                // 13. 服务器确认（核心优化：用临时线程池+超时，避免100%卡住）
                boolean commandCompleted = false;
                UploadStatus finalStatus = UploadStatus.FAILED;
                ExecutorService tempExecutor = Executors.newSingleThreadExecutor(); // 临时线程池（仅用于超时控制）
                try {
                    // 包装 completePendingCommand() 为Future任务，设置超时
                    FTPClient finalFtpClient = ftpClient;
                    Future<Boolean> future = tempExecutor.submit(() -> {
                        try {
                            return finalFtpClient.completePendingCommand();
                        } catch (IOException e) {
                            throw new ExecutionException("服务器确认异常", e);
                        }
                    });

                    // 等待结果，超时则中断
                    commandCompleted = future.get(PENDING_COMMAND_TIMEOUT, TimeUnit.MILLISECONDS);
                } catch (TimeoutException e) {
                    // 超时：强制中断，释放资源
                    tempExecutor.shutdownNow();
                    ftpClient.abort();
                    System.err.println("服务器确认超时（" + PENDING_COMMAND_TIMEOUT / 1000 + "秒）：" + e.getMessage());
                    finalStatus = UploadStatus.SERVER_TIMEOUT;
                } catch (InterruptedException | ExecutionException e) {
                    // 其他异常：中断传输
                    ftpClient.abort();
                    System.err.println("服务器确认异常：" + e.getMessage());
                    finalStatus = UploadStatus.FAILED;
                } finally {
                    tempExecutor.shutdown(); // 关闭临时线程池
                }

                // 14. 结果双重校验（命令响应+文件大小）
                if (commandCompleted && FTPReply.isPositiveCompletion(ftpClient.getReplyCode())) {
                    finalStatus = (uploadedSize.get() == totalSize.get())
                            ? (isResume ? UploadStatus.RESUME_UPLOAD_SUCCESS : UploadStatus.SUCCESS)
                            : UploadStatus.FAILED;
                } else {
                    // 命令未完成，但文件大小匹配 → 视为上传成功（兼容服务器超时）
                    FTPFile[] finalRemoteFiles = ftpClient.listFiles(remoteFileName);
                    if (finalRemoteFiles != null && finalRemoteFiles.length > 0
                            && finalRemoteFiles[0].getSize() == totalSize.get()) {
                        finalStatus = isResume ? UploadStatus.RESUME_UPLOAD_SUCCESS : UploadStatus.SUCCESS;
                    }
                }

                // 设置最终结果
                setResult(finalStatus, finalStatus.getDesc());

            } catch (InterruptedException e) {
                // 线程中断异常（如取消任务）
                setResult(UploadStatus.TASK_CANCELLED, "任务被中断：" + e.getMessage());
                Thread.currentThread().interrupt(); // 恢复中断状态
            } catch (IOException e) {
                // 上传过程IO异常
                String errMsg = "上传异常：" + e.getMessage();
                e.printStackTrace();
                setResult(isResume ? UploadStatus.RESUME_UPLOAD_FAILED : UploadStatus.FAILED, errMsg);
            } finally {
                // 强制释放所有资源（逆序关闭）
                closeStream(outputStream);
                closeStream(inputStream);
                closeFtpClient(ftpClient);
                // 可选：任务完成后移除缓存（避免内存溢出，如需查询历史任务可注释）
                // TASK_CACHE.remove(taskId);
            }
        }

        // 取消任务（线程安全）
        public void cancel() {
            this.cancelled = true;
            this.status.set(UploadStatus.TASK_CANCELLED);
            this.errorMsg = "任务已取消";
            // 取消时触发 latch，唤醒等待线程
            if (resultLatch != null && resultLatch.getCount() > 0) {
                resultLatch.countDown();
            }
        }

        // 设置任务结果（线程安全，触发 latch 和回调）
        private void setResult(UploadStatus status, String errorMsg) {
            this.status.set(status);
            this.errorMsg = errorMsg;
            this.finalResult = new UploadResult(taskId, status, errorMsg);

            // 异步方案：触发回调
            if (resultCallback != null) {
                try {
                    resultCallback.onComplete(finalResult);
                } catch (Exception e) {
                    System.err.println("回调执行失败：" + e.getMessage());
                }
            }

            // 同步方案：触发 latch，唤醒等待线程
            if (resultLatch != null && resultLatch.getCount() > 0) {
                resultLatch.countDown();
            }
        }

        // 获取最终结果（供同步方案调用）
        public UploadResult getFinalResult() {
            return finalResult;
        }

        // Getter（用于查询任务状态）
        public String getTaskId() { return taskId; }
        public UploadStatus getStatus() { return status.get(); }
        public long getUploadedSize() { return uploadedSize.get(); }
        public long getTotalSize() { return totalSize.get(); }
        public String getErrorMsg() { return errorMsg; }
    }

    // ------------------------------ FTP客户端工具方法 ------------------------------
    /**
     * 初始化FTP客户端（带超时+保活配置）
     */
    private static FTPClient createFtpClient() {
        FTPClient ftpClient = new FTPClient();
        ftpClient.setControlEncoding("UTF-8"); // 解决中文文件名乱码
        // 超时配置（连接+数据传输+默认超时）
        ftpClient.setConnectTimeout(DEFAULT_TIMEOUT);
        ftpClient.setDataTimeout(DEFAULT_TIMEOUT);
        ftpClient.setDefaultTimeout(DEFAULT_TIMEOUT);
        // 控制连接保活（每30秒发送NOOP命令，避免服务器断开）
        ftpClient.setControlKeepAliveTimeout(CONTROL_KEEP_ALIVE_TIMEOUT);
        ftpClient.setControlKeepAliveReplyTimeout(10000); // 保活响应超时10秒
        return ftpClient;
    }

    /**
     * 配置FTP上传参数（被动模式+二进制传输，解决防火墙问题）
     */
    private static void configureFtpClient(FTPClient ftpClient) throws IOException {
        ftpClient.setFileType(FTP.BINARY_FILE_TYPE); // 二进制传输（大文件必选）
        ftpClient.setFileTransferMode(FTP.STREAM_TRANSFER_MODE); // 流传输模式
        ftpClient.enterLocalPassiveMode(); // 强制被动模式（避免防火墙拦截）
        ftpClient.setUseEPSVwithIPv4(false); // 禁用EPSV（兼容老旧服务器）
        ftpClient.setActivePortRange(0, 0); // 关闭主动模式，避免端口冲突
        ftpClient.setBufferSize(BUFFER_SIZE); // 设置传输缓冲区大小（与上传缓冲区一致）
    }

    /**
     * 递归创建远程目录（支持多级目录）
     */
    private static boolean createRemoteDirectory(FTPClient ftpClient, String remoteDir) throws IOException {
        if (remoteDir == null || remoteDir.isEmpty() || "/".equals(remoteDir)) {
            return true;
        }
        // 处理Windows路径分隔符
        remoteDir = remoteDir.replace("\\", "/");
        String[] dirs = remoteDir.split("/");
        StringBuilder currentDir = new StringBuilder();

        for (String dir : dirs) {
            if (dir.isEmpty()) {
                continue;
            }
            currentDir.append("/").append(dir);
            // 切换目录失败则创建
            if (!ftpClient.changeWorkingDirectory(currentDir.toString())) {
                if (!ftpClient.makeDirectory(currentDir.toString())) {
                    return false; // 目录创建失败
                }
                ftpClient.changeWorkingDirectory(currentDir.toString());
            }
        }
        return true;
    }

    /**
     * 关闭流资源（通用方法，避免空指针）
     */
    private static void closeStream(Closeable stream) {
        if (stream != null) {
            try {
                stream.close();
            } catch (IOException e) {
                System.err.println("流关闭失败：" + e.getMessage());
            }
        }
    }

    /**
     * 关闭FTP客户端（登出+断开连接，释放资源）
     */
    private static void closeFtpClient(FTPClient ftpClient) {
        if (ftpClient != null && ftpClient.isConnected()) {
            try {
                ftpClient.logout(); // 先登出
            } catch (IOException e) {
                System.err.println("FTP登出失败：" + e.getMessage());
            } finally {
                try {
                    ftpClient.disconnect(); // 再断开连接
                } catch (IOException e) {
                    System.err.println("FTP断开连接失败：" + e.getMessage());
                }
            }
        }
    }

    // ------------------------------ 对外API（同步方案，直接获取最终结果）------------------------------
    public static UploadResult submitUploadTaskSync(
            String ftpHost, int ftpPort, String ftpUsername, String ftpPassword,
            String localFilePath, String remoteDir, String remoteFileName,
            boolean overwrite, UploadProgressListener listener,
            long timeout, TimeUnit unit) {

        // 前置校验：避免无效任务入队
        File localFile = new File(localFilePath);
        if (!localFile.exists() || !localFile.isFile()) {
            String taskId = UUID.randomUUID().toString().replace("-", "");
            return new UploadResult(taskId, UploadStatus.FILE_NOT_FOUND, "本地文件不存在：" + localFilePath);
        }
        if (localFile.length() <= 0) {
            String taskId = UUID.randomUUID().toString().replace("-", "");
            return new UploadResult(taskId, UploadStatus.FAILED, "文件大小为0，无法上传");
        }

        // 创建 CountDownLatch（同步等待核心）
        CountDownLatch resultLatch = new CountDownLatch(1);
        // 创建上传任务（传入 latch）
        UploadTask task = new UploadTask(
                ftpHost, ftpPort, ftpUsername, ftpPassword,
                localFilePath, remoteDir, remoteFileName,
                overwrite, listener,
                resultLatch
        );

        try {
            // 提交任务到线程池
            UPLOAD_EXECUTOR.submit(task);
            // 阻塞等待最终结果（超时时间由调用方指定）
            if (resultLatch.await(timeout, unit)) {
                return task.getFinalResult() != null ? task.getFinalResult() :
                        new UploadResult(task.getTaskId(), UploadStatus.FAILED, "未知错误");
            } else {
                // 超时，取消任务并返回超时结果
                cancelTask(task.getTaskId());
                return new UploadResult(task.getTaskId(), UploadStatus.FAILED, "上传超时（" + timeout + unit.name() + "）");
            }
        } catch (InterruptedException e) {
            cancelTask(task.getTaskId());
            Thread.currentThread().interrupt();
            return new UploadResult(task.getTaskId(), UploadStatus.TASK_CANCELLED, "任务被中断：" + e.getMessage());
        } catch (Exception e) {
            return new UploadResult(task.getTaskId(), UploadStatus.FAILED, "任务执行失败：" + e.getMessage());
        } finally {
            // 防止遗漏，确保 latch 最终会被触发
            if (resultLatch.getCount() > 0) {
                resultLatch.countDown();
            }
        }
    }

    // ------------------------------ 对外API（异步方案，回调获取最终结果）------------------------------
    public static UploadResult submitUploadTaskAsync(
            String ftpHost, int ftpPort, String ftpUsername, String ftpPassword,
            String localFilePath, String remoteDir, String remoteFileName,
            boolean overwrite, UploadProgressListener listener,
            UploadResultCallback resultCallback) {

        // 前置校验
        File localFile = new File(localFilePath);
        if (!localFile.exists() || !localFile.isFile()) {
            String taskId = UUID.randomUUID().toString().replace("-", "");
            UploadResult result = new UploadResult(taskId, UploadStatus.FILE_NOT_FOUND, "本地文件不存在：" + localFilePath);
            resultCallback.onComplete(result);
            return result;
        }
        if (localFile.length() <= 0) {
            String taskId = UUID.randomUUID().toString().replace("-", "");
            UploadResult result = new UploadResult(taskId, UploadStatus.FAILED, "文件大小为0，无法上传");
            resultCallback.onComplete(result);
            return result;
        }

        // 创建上传任务（传入回调）
        UploadTask task = new UploadTask(
                ftpHost, ftpPort, ftpUsername, ftpPassword,
                localFilePath, remoteDir, remoteFileName,
                overwrite, listener,
                resultCallback
        );

        try {
            UPLOAD_EXECUTOR.submit(task);
            return new UploadResult(task.getTaskId(), UploadStatus.UPLOADING, "任务已提交，上传中");
        } catch (Exception e) {
            UploadResult result = new UploadResult(task.getTaskId(), UploadStatus.FAILED, "任务提交失败：" + e.getMessage());
            resultCallback.onComplete(result);
            return result;
        }
    }

    // ------------------------------ 对外API（查询任务状态）------------------------------
    public static UploadTask queryTaskStatus(String taskId) {
        return TASK_CACHE.get(taskId);
    }

    // ------------------------------ 对外API（取消任务）------------------------------
    public static boolean cancelTask(String taskId) {
        UploadTask task = TASK_CACHE.get(taskId);
        if (task == null) {
            return false;
        }
        UploadStatus status = task.getStatus();
        if (status == UploadStatus.UPLOADING) {
            task.cancel();
            return true;
        }
        return false;
    }

    // ------------------------------ 对外API（关闭线程池）------------------------------
    public static void shutdown() {
        UPLOAD_EXECUTOR.shutdown();
        try {
            // 等待10分钟，让正在执行的任务完成
            if (!UPLOAD_EXECUTOR.awaitTermination(10, TimeUnit.MINUTES)) {
                UPLOAD_EXECUTOR.shutdownNow(); // 强制关闭未完成的任务
            }
        } catch (InterruptedException e) {
            UPLOAD_EXECUTOR.shutdownNow();
            Thread.currentThread().interrupt();
        }
        System.out.println("FTP上传线程池已关闭");
    }

    // ------------------------------ 测试方法（直接运行即可测试）------------------------------
    public static void main(String[] args) {
        // 配置参数（替换为你的实际FTP信息和文件路径）
        String ftpHost = "202.108.199.26";
        int ftpPort = 21;
        String ftpUsername = "cloudtest";
        String ftpPassword = "CloudTest!95";
        String localFilePath = "E:\\nc\\GRAPES\\CMA_BEN_GRAPESGFS_GLDT_2025111300_240h_SSW_calculate.nc"; // 200M大文件
        String remoteDir = "/nc/GRAPES/"; // 远程目录（自动创建）
        String remoteFileName = "CMA_BEN_GRAPESGFS_GLDT_2025111300_240h_SSW_calculate.nc"; // 远程文件名
        boolean overwrite = false; // 不覆盖，支持断点续传

        // 测试同步方案（直接获取最终结果）
        System.out.println("=== 同步方案测试 ===");
        UploadResult finalResult = submitUploadTaskSync(
                ftpHost, ftpPort, ftpUsername, ftpPassword,
                localFilePath, remoteDir, remoteFileName,
                overwrite,
                (uploadedSize, totalSize, progress) -> {
                    // 实时打印进度
                    long uploadedMB = uploadedSize / (1024 * 1024);
                    long totalMB = totalSize / (1024 * 1024);
                    System.out.printf("[进度] %.2f%% | 已传：%dMB | 总大小：%dMB%n", progress, uploadedMB, totalMB);
                },
                1, TimeUnit.HOURS // 超时时间：1小时
        );

        // 打印最终结果
        System.out.println("\n=== 最终上传结果 ===");
        System.out.println("任务ID：" + finalResult.getTaskId());
        System.out.println("状态：" + finalResult.getStatus().getDesc());
        System.out.println("描述：" + finalResult.getMessage());

        // 程序退出时关闭线程池
        shutdown();
    }
}